import java.util.HashSet;
import java.util.Set;

import org.gearman.client.GearmanIOEventListener;
import org.gearman.client.GearmanJobResult;
import org.gearman.client.GearmanJobResultImpl;
import org.gearman.common.GearmanPacket;
import org.gearman.common.GearmanPacketImpl;
import org.gearman.common.GearmanPacketMagic;
import org.gearman.common.GearmanPacketType;
import org.gearman.worker.GearmanFunction;


public abstract class AbstractWorkerFunction implements GearmanFunction{
	protected Object data;
	protected final String name;
	protected byte[] jobHandle;
    protected Set<GearmanIOEventListener> listeners;
	
	
    public AbstractWorkerFunction() {
        this(null);
    }
    
    public AbstractWorkerFunction(String name) {
    	listeners = new HashSet<GearmanIOEventListener>();
        jobHandle = new byte[0];
        if (name == null) {
            this.name = this.getClass().getCanonicalName();
        } else {
            this.name = name;
        }
    }
    
    public abstract GearmanJobResult executeFunction();
    
	@Override
	public GearmanJobResult call() throws Exception {
		System.out.println("Worker is working...");
	    GearmanPacket event = null;
        GearmanJobResult result = null;
        Exception thrown = null;
        try {
            result = executeFunction();
        } catch (Exception e) {
            thrown = e;
        }
        
        if (result == null) {
            String message = thrown == null ? "function returned null result" : thrown.getMessage();
            if (message == null) {
                message = thrown.toString();
            }
            fireEvent(new GearmanPacketImpl(GearmanPacketMagic.REQ, GearmanPacketType.WORK_EXCEPTION,
                    GearmanPacketImpl.generatePacketData(jobHandle, message.getBytes())));
            result = new GearmanJobResultImpl(jobHandle, false, new byte[0], new byte[0], new byte[0], -1, -1);
        }

        if (result.jobSucceeded()) {
            event = new GearmanPacketImpl(GearmanPacketMagic.REQ, GearmanPacketType.WORK_COMPLETE, 
            		GearmanPacketImpl.generatePacketData(jobHandle, result.getResults()));
        } else {
            event = new GearmanPacketImpl(GearmanPacketMagic.REQ,GearmanPacketType.WORK_FAIL, jobHandle);

        }
        
        fireEvent(event);
        
        return result;
	}

	@Override
	public void fireEvent(GearmanPacket event) {
		System.out.println("Worker fireEvent: " + event);
		if (event == null) {
            throw new IllegalArgumentException("event can not be null");
        }
        for (GearmanIOEventListener listener : listeners) {
            listener.handleGearmanIOEvent(event);
        }
	}

	@Override
	public byte[] getJobHandle() {
		System.out.println("Worker getJobHandle: ");
		return null;
	}

	@Override
	public String getName() {
		System.out.println("Worker getName: ");
		return null;
	}

	@Override
	public void registerEventListener(GearmanIOEventListener listener)
			throws IllegalArgumentException {		
		System.out.println("Worker registerEventListener: ");
		if (listener == null) {
            throw new IllegalArgumentException("listener can not be null");
        }
		listeners.add(listener);
		
	}

	@Override
	public void setData(Object data) {
		this.data = data;
		System.out.println("Worker setData: " + data);
		
	}

	@Override
	public void setJobHandle(byte[] handle) throws IllegalArgumentException {
		System.out.println("Worker setJobHandle: " + new String(handle));
		if (handle == null) {
            throw new IllegalArgumentException("handle can not be null");
        }
        if (handle.length == 0) {
            throw new IllegalArgumentException("handle can not be empty");
        }
        jobHandle = new byte[handle.length];
        System.arraycopy(handle, 0, jobHandle, 0, handle.length);
	}
	

}
